﻿using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace AlternativePorts
{
	public class PortTpl<T>
	{
		private Queue<T> q = new Queue<T>();
		private ReceiveMode mode = ReceiveMode.Sequential;
		private Action<T> action;
		private bool workingOnQueue;

		public void Post(T item)
		{
			if (mode == ReceiveMode.Parallel)
				PostParallel(item);
			else
				PostSeqential(item);
		}

		private void PostSeqential(T item)
		{
			q.Enqueue(item);
			WorkOnQueue(true);
		}

		private void WorkOnQueue(bool start)
		{
			T item = default(T);
			lock (q)
			{
				if (start && workingOnQueue)
					return;
				if (q.Count > 0)
					item = q.Dequeue();
				else
				{
					workingOnQueue = false;
					return;
				}
				workingOnQueue = true;
			}
			Task.Factory.StartNew(() => { action(item); WorkOnQueue(false); });
		}

		public void PostParallel(T item)
		{
			if (action != null)
				Task.Factory.StartNew(() => action(item));
		}

		public void Receive(Action<T> action, ReceiveMode mode)
		{
			this.action = action;
			this.mode = mode;
		}

		public void Send(T item)
		{
			action(item);
		}
	}
}
